﻿/*
 * Created by SharpDevelop.
 * User: Eddie
 * Date: 4/14/2012
 * Time: 10:42 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */
using System;
using System.IO;

namespace PathFinder
{
    /* @class BitMap
	 * 
     * @brief
     * A class that takes input from a bmp and transforms each pixel into a node. Also, writes to a bitmap based on the nodal information.
     */
    public class BitMap {
        
        // This is a test function so no comments :p
        public Node [,] BitMapTest (String bmpFile)
        {
            byte [,,] mapArray = openFile (bmpFile);
            Node [,] nodes = translateToMap(mapArray);
            outputBMP (mapArray, nodes, bmpFile);
            return nodes;
        }
    
        /* Opens a 24bit bmp and retuns the byte values of each pixel
	     * 
         * @param
         * bmpFile The file to open.
         * 
         * @return
         * A 3d array that represents each pixel. The first 2 elements are the coordinates and the last one represents bytes in the pixel.
	     */
        public byte [,,] openFile (String bmpFile)
        {
            try
            {
                BinaryReader input = new BinaryReader(File.Open(bmpFile, FileMode.Open));   //open the file
                int length = (int)input.BaseStream.Length;                                  //length of file
                byte [] imageData = new byte[length];                                       //stores the bytes of the file
                byte [,,] outputArray;                                                      //the output
                int c;                                                                      // length of the header
                
                // header information from the bmp
                ushort type;
                uint size;
                ushort reserve1;
                ushort reserve2;
                uint offBits;
                uint biSize;
                uint biWidth;
                uint biHeight;
                ushort biPlanes;
                ushort biBitCount;
                uint biCompression;
                uint biSizeImage;
                uint biXPelsPerMeter;
                uint biYPelsPerMeter;
                uint biClrUsed;
                uint biClrImportant;
            
                // reads the bmp into imageData
                for (int i=0; i<length;i++)
                {
                    imageData [i] = input.ReadByte();
                }
                input.Close();
                
                // initializes the header variables
                type=(ushort)(imageData[1]*256+imageData[0]);
                size=(uint)(imageData[2]+256*(imageData[3]+256*(imageData[4]+imageData[5]*256)));
                reserve1=(ushort)(imageData[7]*256+imageData[6]);
                reserve2=(ushort)(imageData[9]*256+imageData[8]);
                offBits=(uint)(imageData[10]+256*(imageData[11]+256*(imageData[12]+imageData[13]*256)));
                biSize=(uint)(imageData[14]+256*(imageData[15]+256*(imageData[16]+imageData[17]*256)));
                biWidth=(uint)(imageData[18]+256*(imageData[19]+256*(imageData[20]+imageData[21]*256)));
                biHeight=(uint)(imageData[22]+256*(imageData[23]+256*(imageData[24]+imageData[25]*256)));
                biPlanes=(ushort)(imageData[27]*256+imageData[26]);
                biBitCount=(ushort)(imageData[29]*256+imageData[28]);;
                biCompression=(uint)(imageData[30]+256*(imageData[31]+256*(imageData[32]+imageData[33]*256)));
                biSizeImage=(uint)(imageData[34]+256*(imageData[35]+256*(imageData[36]+imageData[37]*256)));
                biXPelsPerMeter=(uint)(imageData[38]+256*(imageData[39]+256*(imageData[40]+imageData[41]*256)));
                biYPelsPerMeter=(uint)(imageData[42]+256*(imageData[43]+256*(imageData[44]+imageData[45]*256)));
                biClrUsed=(uint)(imageData[46]+256*(imageData[47]+256*(imageData[48]+imageData[49]*256)));
                biClrImportant=(uint)(imageData[50]+256*(imageData[51]+256*(imageData[52]+imageData[53]*256)));
                    
                // initializes variables based on the header information
                outputArray = new byte [biWidth,biHeight,3];
                c = (int) offBits;
                
                // writes information into the output array
                for (int i=0;i<biHeight;i++)
                {
                    for (int j=0;j<biWidth;j++)
                    {
                        for (int k=0;k<3;k++)
                        {
                            outputArray [j,i,k] = imageData [c];
                            c++;
                        }
                    }
                    for (int j=0;j<(biWidth*3)%4;j++)
                    {
                         c++;
                    }
                }
                return outputArray;
            }
            catch (Exception e)
            {
                Console.WriteLine (e);
                return null;
            }
        }
    
        /* Converts an array of bytes to a map of nodes.
	     * 
         * @param
         * mapArray A 3d array of nodes to traverse.
         * 
         * @return
         * A 2D array of nodes.
	     */
        public Node [,] translateToMap (byte [,,] mapArray)
        {
            Node [,] nodes = new Node [mapArray.GetLength(0),mapArray.GetLength(1)];
            
            for (int i=0;i<mapArray.GetLength(0);i++)
            {
                for (int j=0;j<mapArray.GetLength(1);j++)
                {
                    nodes [i,j] = new Node ();
                    // checks if the node is traverseable
                    if (mapArray[i,j,0] == 0xFF && mapArray[i,j,1] == 0xFF && mapArray[i,j,2] == 0xFF)
                    {
                        nodes [i,j].traverse = true;
                    }
                }
            }
            return nodes;
        }
    
        // this outputs to a bmp, not so sure if it's going to be in the final project; so far it's only used for testing....
        public void outputBMP (byte [,,] mapArray, Node [,] nodes, string fileName)
        {
            FileStream stream = new FileStream("output_"+fileName, FileMode.Create);
            BinaryReader reader = new BinaryReader(File.Open(fileName, FileMode.Open));
            BinaryWriter writer = new BinaryWriter(stream);
            
            writer.Write(reader.ReadBytes(54));
            reader.Close ();
            
            for (int i=0;i<nodes.GetLength(1);i++)
            {
                for (int j=0;j<nodes.GetLength(0);j++)
                {
                    if (nodes [j,i].visited == true && nodes [j,i].path == false)
                    {
                        nodes [j,i].testPoint = true;
                    }
                    
                    if (nodes[j,i].testPoint==true)
                    {
                        writer.Write ((byte)0x64);
                        writer.Write ((byte)0x00);
                        writer.Write ((byte)0x00);
                    }
                    else if (nodes[j,i].traverse==true && nodes[j,i].path==false)
                    {
                        writer.Write ((byte)0xFF);
                        writer.Write ((byte)0xFF);
                        writer.Write ((byte)0xFF);
                    }
                    else if (nodes[j,i].path==true)
                    {
                        writer.Write ((byte)0x00);
                        writer.Write ((byte)0x00);
                        writer.Write ((byte)0x64);
                    } 
                    else if (nodes[j,i].traverse==false)
                    {
                        writer.Write ((byte)0x55);
                        writer.Write ((byte)0x55);
                        writer.Write ((byte)0x55);
                    }
                }
                for (int j = 0;j<(nodes.GetLength(0)*3)%4;j++)
                {
                    writer.Write((byte)0x00);
                }
            }
            writer.Close();
        }
    }
}
